

<!DOCTYPE html>
<html lang="zh-CN" data-default-color-scheme=auto>



<head>
  <meta charset="UTF-8">
  <link rel="apple-touch-icon" sizes="76x76" href="/img/favicon.png">
  <link rel="icon" href="/img/favicon.png">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0, shrink-to-fit=no">
  <meta http-equiv="x-ua-compatible" content="ie=edge">
  
  <meta name="theme-color" content="#2f4154">
  <meta name="author" content="Cai Shibo">
  <meta name="keywords" content="cc">
  
    <meta name="description" content="🌈 本文内容来自于JavaGuide中的内容，整理了Java面试的重点内容，更多细节还是要靠平时的钻研和积累。✊🏻">
<meta property="og:type" content="article">
<meta property="og:title" content="Java基础&amp;容器-Java">
<meta property="og:url" content="https://hahsx_xd.gitee.io/2022/03/31/%E5%9F%BA%E7%A1%80-Java/index.html">
<meta property="og:site_name" content="🍊CAI SHIBO🥬">
<meta property="og:description" content="🌈 本文内容来自于JavaGuide中的内容，整理了Java面试的重点内容，更多细节还是要靠平时的钻研和积累。✊🏻">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://hahsx_xd.gitee.io/images/pasted-67.png">
<meta property="og:image" content="https://hahsx_xd.gitee.io/images/pasted-68.png">
<meta property="og:image" content="https://hahsx_xd.gitee.io/images/pasted-69.png">
<meta property="og:image" content="https://hahsx_xd.gitee.io/images/pasted-70.png">
<meta property="og:image" content="https://hahsx_xd.gitee.io/images/pasted-71.png">
<meta property="og:image" content="https://hahsx_xd.gitee.io/images/pasted-72.png">
<meta property="article:published_time" content="2022-03-31T12:53:00.000Z">
<meta property="article:modified_time" content="2022-11-29T07:14:46.501Z">
<meta property="article:author" content="Cai Shibo">
<meta property="article:tag" content="实习面试">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://hahsx_xd.gitee.io/images/pasted-67.png">
  
  
  <title>Java基础&amp;容器-Java - 🍊CAI SHIBO🥬</title>

  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/css/bootstrap.min.css" />


  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css@4/github-markdown.min.css" />
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/hint.css@2/hint.min.css" />

  
    
    
      
      <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js@10/styles/github-gist.min.css" />
    
  

  
    <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.css" />
  


<!-- 主题依赖的图标库，不要自行修改 -->

<link rel="stylesheet" href="//at.alicdn.com/t/font_1749284_ba1fz6golrf.css">



<link rel="stylesheet" href="//at.alicdn.com/t/font_1736178_lbnruvf0jn.css">


<link  rel="stylesheet" href="/css/main.css" />

<!-- 自定义样式保持在最底部 -->


  <script id="fluid-configs">
    var Fluid = window.Fluid || {};
    var CONFIG = {"hostname":"hahsx_xd.gitee.io","root":"/","version":"1.8.14","typing":{"enable":true,"typeSpeed":70,"cursorChar":".|","loop":false},"anchorjs":{"enable":true,"element":"h1,h2,h3,h4,h5,h6","placement":"right","visible":"hover","icon":"#"},"progressbar":{"enable":true,"height_px":3,"color":"#29d","options":{"showSpinner":false,"trickleSpeed":100}},"copy_btn":true,"image_zoom":{"enable":true,"img_url_replace":["",""]},"toc":{"enable":true,"headingSelector":"h1,h2,h3,h4,h5,h6","collapseDepth":5},"lazyload":{"enable":true,"loading_img":"/img/loading.gif","onlypost":true,"offset_factor":2},"web_analytics":{"enable":false,"baidu":null,"google":null,"gtag":null,"tencent":{"sid":null,"cid":null},"woyaola":null,"cnzz":null,"leancloud":{"app_id":null,"app_key":null,"server_url":null,"path":"window.location.pathname","ignore_local":false}},"search_path":"/local-search.xml"};
  </script>
  <script  src="/js/utils.js" ></script>
  <script  src="/js/color-schema.js" ></script>
<meta name="generator" content="Hexo 5.4.0"><link rel="alternate" href="/atom.xml" title="🍊CAI SHIBO🥬" type="application/atom+xml">
</head>


<body>
  <header style="height: 70vh;">
    <nav id="navbar" class="navbar fixed-top  navbar-expand-lg navbar-dark scrolling-navbar">
  <div class="container">
    <a class="navbar-brand" href="/">
      <strong>^_^ 🥬 CC</strong>
    </a>

    <button id="navbar-toggler-btn" class="navbar-toggler" type="button" data-toggle="collapse"
            data-target="#navbarSupportedContent"
            aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
      <div class="animated-icon"><span></span><span></span><span></span></div>
    </button>

    <!-- Collapsible content -->
    <div class="collapse navbar-collapse" id="navbarSupportedContent">
      <ul class="navbar-nav ml-auto text-center">
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/">
                <i class="iconfont icon-home-fill"></i>
                首页
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/archives/">
                <i class="iconfont icon-archive-fill"></i>
                归档
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/categories/">
                <i class="iconfont icon-category-fill"></i>
                分类
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/tags/">
                <i class="iconfont icon-tags-fill"></i>
                标签
              </a>
            </li>
          
        
          
          
          
          
            <li class="nav-item">
              <a class="nav-link" href="/about/">
                <i class="iconfont icon-user-fill"></i>
                关于
              </a>
            </li>
          
        
        
          <li class="nav-item" id="search-btn">
            <a class="nav-link" target="_self" href="javascript:;" data-toggle="modal" data-target="#modalSearch" aria-label="Search">
              &nbsp;<i class="iconfont icon-search"></i>&nbsp;
            </a>
          </li>
        
        
          <li class="nav-item" id="color-toggle-btn">
            <a class="nav-link" target="_self" href="javascript:;" aria-label="Color Toggle">&nbsp;<i
                class="iconfont icon-dark" id="color-toggle-icon"></i>&nbsp;</a>
          </li>
        
      </ul>
    </div>
  </div>
</nav>

    <div class="banner" id="banner" parallax=true
         style="background: url('/img/default.png') no-repeat center center;
           background-size: cover;">
      <div class="full-bg-img">
        <div class="mask flex-center" style="background-color: rgba(0, 0, 0, 0.3)">
          <div class="page-header text-center fade-in-up">
            <span class="h2" id="subtitle" title="Java基础&amp;容器-Java">
              
            </span>

            
              <div class="mt-3">
  
    <span class="post-meta mr-2">
      <i class="iconfont icon-author" aria-hidden="true"></i>
      Cai Shibo
    </span>
  
  
    <span class="post-meta">
      <i class="iconfont icon-date-fill" aria-hidden="true"></i>
      <time datetime="2022-03-31 20:53" pubdate>
        2022年3月31日 晚上
      </time>
    </span>
  
</div>

<div class="mt-1">
  
    <span class="post-meta mr-2">
      <i class="iconfont icon-chart"></i>
      8.1k 字
    </span>
  

  
    <span class="post-meta mr-2">
      <i class="iconfont icon-clock-fill"></i>
      
      
      41 分钟
    </span>
  

  
  
    
      <!-- 不蒜子统计文章PV -->
      <span id="busuanzi_container_page_pv" style="display: none">
        <i class="iconfont icon-eye" aria-hidden="true"></i>
        <span id="busuanzi_value_page_pv"></span> 次
      </span>
    
  
</div>

            
          </div>

          
        </div>
      </div>
    </div>
  </header>

  <main>
    
      

<div class="container-fluid nopadding-x">
  <div class="row nomargin-x">
    <div class="d-none d-lg-block col-lg-2"></div>
    <div class="col-lg-8 nopadding-x-md">
      <div class="container nopadding-x-md" id="board-ctn">
        <div class="py-5" id="board">
          <article class="post-content mx-auto">
            <!-- SEO header -->
            <h1 style="display: none">Java基础&amp;容器-Java</h1>
            
              <p class="note note-info">
                
                  最后更新：23 天前
                
              </p>
            
            <div class="markdown-body">
              <p><strong>🌈 本文内容来自于JavaGuide中的内容，整理了Java面试的重点内容，更多细节还是要靠平时的钻研和积累。✊🏻</strong></p>
<span id="more"></span>

<hr>
<h3 id="Java-基础"><a href="#Java-基础" class="headerlink" title="Java 基础"></a>Java 基础</h3><h4 id="Java语言特点"><a href="#Java语言特点" class="headerlink" title="Java语言特点"></a>Java语言特点</h4><ol>
<li><p>面向对象（封装，继承，多态）</p>
</li>
<li><p>平台无关性：通过javac编译成.class文件，JVM运行Java字节码。JVM类加载器先加载字节码文件，再通过解释器一句一句解释执行，执行速度相对会慢一些（<strong>Java慢于C的主要原因</strong>）。引进<strong>JIT，运行时编译热点代码</strong>，并将其字节码对应的机器码保存下来。</p>
</li>
<li><p>支持多线程</p>
</li>
<li><p>支持网络编程</p>
</li>
<li><p>编译与解释并存：Java 语言既具有编译型语言的特征，也具有解释型语言的特征。因为 Java 程序要经过先编译，后解释两个步骤，由 Java 编写的程序需要先经过编译步骤，生成字节码（.class 文件），这种字节码必须由Java 解释器来解释执行。</p>
</li>
</ol>
<hr>
<h4 id="Java和C-的区别"><a href="#Java和C-的区别" class="headerlink" title="Java和C++的区别"></a>Java和C++的区别</h4><p>Java 和 C++ 都是面向对象的语言，都支持封装、继承和多态。</p>
<ul>
<li>Java 不提供指针来直接访问内存，程序内存更加安全。</li>
<li>Java 的类是单继承的，C++ 支持多重继承；虽然 Java 的类不可以多继承，但是接口可以多继承。</li>
<li>Java 有自动内存管理垃圾回收机制(GC)，不需要程序员手动释放无用内存。</li>
<li>C++ 同时支持方法重载和操作符重载，但是 Java 只支持方法重载（操作符重载增加了复杂性，这与 Java 最初的设计思想不符）。</li>
</ul>
<hr>
<h4 id="静态方法不能调用非静态成员"><a href="#静态方法不能调用非静态成员" class="headerlink" title="静态方法不能调用非静态成员"></a>静态方法不能调用非静态成员</h4><ul>
<li>静态方法是属于类的，<strong>在类加载的时候就会分配内存</strong>，可以通过类名直接访问。而非静态成员属于实例对象，只有<strong>在对象实例化之后才存在</strong>，需要通过类的实例对象去访问。</li>
<li><strong>类的非静态成员不存在的时候静态成员就已存在</strong>，此时调用在内存中还不存在的非静态成员，属于非法操作。</li>
</ul>
<hr>
<h4 id="重载与重写"><a href="#重载与重写" class="headerlink" title="重载与重写"></a>重载与重写</h4><p>重载发生在编译期，重写发生在运行期。  </p>
<ol>
<li>在编译过程中，编译器必须根据参数类型以及长度来确定到底是调用的哪个方法，这也是Java编译时多态的体现。  </li>
<li>但是不知道调用的是父类的方法还是子类的方法，只有在实际运行的时候才知道应该调用哪个方法，这个也是java运行时多态的体现。  </li>
</ol>
<p>方法的重写要遵循“两同两小一大”</p>
<ul>
<li>“两同”即方法名相同、形参列表相同；</li>
<li>“两小”指的是子类方法返回值类型应比父类方法返回值类型更小或相等，子类方法声明抛出的异常类应比父类方法声明抛出的异常类更小或相等；</li>
<li>“一大”指的是子类方法的访问权限应比父类方法的访问权限更大或相等。</li>
</ul>
<hr>
<h4 id="基本类型和包装类型"><a href="#基本类型和包装类型" class="headerlink" title="基本类型和包装类型"></a>基本类型和包装类型</h4><table>
<thead>
<tr>
<th align="center">基本类型</th>
<th align="center">位数</th>
<th align="center">字节</th>
<th align="center">默认值</th>
<th align="center">取值范围</th>
</tr>
</thead>
<tbody><tr>
<td align="center">byte</td>
<td align="center">8</td>
<td align="center">1</td>
<td align="center">0</td>
<td align="center">-128 ~ 127</td>
</tr>
<tr>
<td align="center">short</td>
<td align="center">16</td>
<td align="center">2</td>
<td align="center">0</td>
<td align="center">-32768 ~ 32767</td>
</tr>
<tr>
<td align="center">int</td>
<td align="center">32</td>
<td align="center">4</td>
<td align="center">0</td>
<td align="center">-2147483648 ~ 2147483647</td>
</tr>
<tr>
<td align="center">long</td>
<td align="center">64</td>
<td align="center">8</td>
<td align="center">0L</td>
<td align="center">-9223372036854775808 ~ 9223372036854775807</td>
</tr>
<tr>
<td align="center">char</td>
<td align="center">16</td>
<td align="center">2</td>
<td align="center">‘u0000’</td>
<td align="center">0 ~ 65535</td>
</tr>
<tr>
<td align="center">float</td>
<td align="center">32</td>
<td align="center">4</td>
<td align="center">0f</td>
<td align="center">1.4E-45 ~ 3.4028235E38</td>
</tr>
<tr>
<td align="center">double</td>
<td align="center">64</td>
<td align="center">8</td>
<td align="center">0d</td>
<td align="center">4.9E-324 ~ 1.7976931348623157E308</td>
</tr>
<tr>
<td align="center">boolean</td>
<td align="center">1</td>
<td align="center"></td>
<td align="center">false</td>
<td align="center">true、false</td>
</tr>
</tbody></table>
<p><strong>包装类型</strong>：Byte、Short、Integer、Long、Float、Double、Character、Boolean</p>
<ul>
<li>包装类型不赋值就是 null ，而基本类型有默认值且不是 null。</li>
<li>包装类型可用于泛型，而基本类型不可以。</li>
<li>基本数据类型的<strong>局部变量</strong>存放在 Java 虚拟机<strong>栈</strong>中的局部变量表中，基本数据类型的<strong>成员变量（未被 static 修饰，规范：修饰应该使用包装类型 ）</strong>存放在 Java 虚拟机的<strong>堆</strong>中。包装类型属于对象类型，几乎所有对象实例都存在于堆中。</li>
<li>相比于对象类型， 基本数据类型占用的空间非常小。</li>
</ul>
<hr>
<h4 id="常量池技术"><a href="#常量池技术" class="headerlink" title="常量池技术"></a>常量池技术</h4><p>除了Float、Double，其他包装类实现了常量池技术，Integer i = 12；其实是<strong>调用valueOf()方法</strong>，然后<strong>使用IntegerCache（堆上</strong>）里的对象。<br>如果 new 一个新对象，使用 ‘==’ 判断是不相等，equals() 相等。  </p>
<p><em>Byte,Short,Integer,Long 这 4 种包装类默认创建了数值 [-128，127] 的相应类型的缓存数据，Character 创建了数值在 [0,127] 范围的缓存数据，Boolean 直接返回 True or False。</em></p>
<hr>
<h4 id="字符串常量池"><a href="#字符串常量池" class="headerlink" title="字符串常量池"></a>字符串常量池</h4><p>Java为String在<strong>堆（1.7之前放在方法区）中</strong>开辟的一块内存缓冲区，为了提高性能同时减少内存开销。在JVM中，字符串常量池由一个hash表实现。默认容量为60013（JDK7u40前为1009），一定要为素数。当字符串常量池中的存储比较多的字符串时，会导致hash冲突，从而每个节点形成长长的链表，导致性能下降。所以在使用字符串常量池时，一定要控制容量。</p>
<hr>
<h4 id="String"><a href="#String" class="headerlink" title="String"></a>String</h4><p>String 类中使用 <strong>final 关键字修饰字符数组</strong>来保存字符串，final 不是其不可变的根本原因，因为 final 只限定了其引用的 char[] 对象不能修改，但是 char[] 本身的内容是可以修改的。String 不能变化的根本原因是：</p>
<ul>
<li>保存字符串的数组被 final 修饰且为私有的，并且String 类没有提供/暴露修改这个字符串的方法。</li>
<li>String 类被 final 修饰导致其不能被继承，进而避免了子类破坏 String 不可变。</li>
</ul>
<hr>
<h4 id="自动装箱拆箱"><a href="#自动装箱拆箱" class="headerlink" title="自动装箱拆箱"></a>自动装箱拆箱</h4><p>装箱：包装类的valueOf () 方法，Integer.valueOf (10)；<br>拆箱：xxxValue () 方法，**包装类对象 . **intValue ()。</p>
<p>频繁拆装箱消耗资源，尽量避免不必要的该类操作。</p>
<hr>
<h4 id="引用拷贝、浅拷贝、深拷贝"><a href="#引用拷贝、浅拷贝、深拷贝" class="headerlink" title="引用拷贝、浅拷贝、深拷贝"></a>引用拷贝、浅拷贝、深拷贝</h4><ul>
<li><p>引用拷贝：在<strong>栈</strong>上生成一个<strong>新的对象引用地址</strong>，指向堆中的同一个对象。<br><img src="/images/pasted-67.png" srcset="/img/loading.gif" lazyload alt="引用拷贝"></p>
</li>
<li><p>浅拷贝：在<strong>堆</strong>上创建一个<strong>新对象</strong>，新对象和原对象不等，但是新对象的属性和老对象相同（属性是基本类型拷贝的就是基本类型的值；属性是引用类型，拷贝的就是内存地址）。<br><img src="/images/pasted-68.png" srcset="/img/loading.gif" lazyload alt="浅拷贝"></p>
</li>
<li><p>深拷贝：在<strong>堆</strong>创建了一个<strong>新对象，并且复制其内的成员变量。</strong><br><img src="/images/pasted-69.png" srcset="/img/loading.gif" lazyload alt="深拷贝"></p>
</li>
</ul>
<hr>
<h4 id="泛型"><a href="#泛型" class="headerlink" title="泛型"></a>泛型</h4><p>泛型提供了<strong>编译时类型安全检测机制</strong>，该机制允许程序员在编译时检测到非法的类型。泛型的本质是<strong>参数化类型</strong>。</p>
<p><strong>类型擦除</strong>：Java的泛型是伪泛型，在运行期间泛型信息都会被擦除，即被实际的类型替代。</p>
<hr>
<h4 id="反射"><a href="#反射" class="headerlink" title="反射"></a>反射</h4><ul>
<li>优点：代码更加灵活、为各种框架提供开箱即用的功能提供了便利</li>
<li>缺点：运行时有了分析操作类的能力，这同样也增加了安全问题。比如可以无视泛型参数的安全检查（泛型参数的安全检查发生在编译时）。另外，反射的性能也要稍差点，不过，对于框架来说实际是影响不大的。</li>
</ul>
<p><strong>动态代理依赖于反射、注解实现用到了反射。</strong></p>
<hr>
<h4 id="注解-Annotation"><a href="#注解-Annotation" class="headerlink" title="注解 Annotation"></a>注解 Annotation</h4><p>作用：</p>
<ul>
<li>编译检查</li>
<li>( 平时和框架 ) 提高开发效率，使代码更易懂</li>
</ul>
<p>注解要被解析才可以生效。</p>
<ul>
<li>编译期直接扫描：编译器在编译 Java 代码的时候扫描对应的注解并处理，比如某个方法使用@Override 注解，编译器在编译的时候就会检测当前的方法是否重写了父类对应的方法。</li>
<li>运行期通过反射处理：像框架中自带的注解(比如 Spring 框架的 @Value 、@Component)都是通过反射来进行处理的。</li>
</ul>
<hr>
<h4 id="字节流、字符流"><a href="#字节流、字符流" class="headerlink" title="字节流、字符流"></a>字节流、字符流</h4><p>字符流是由 Java 虚拟机将字节转换得到的，这个过程比较<strong>耗时</strong>，并且我们不知道编码类型就很<strong>容易出现乱码问题</strong>。所以 I/O 流就干脆提供了一个直接操作字符的接口，方便我们平时对字符进行流操作。如果音频文件、图片等媒体文件用字节流比较好，如果涉及到字符的话使用字符流比较好。</p>
<hr>
<h4 id="Java只有值传递"><a href="#Java只有值传递" class="headerlink" title="Java只有值传递"></a>Java只有值传递</h4><ul>
<li>值传递 ：方法接收的是实参值的拷贝，会创建副本。</li>
<li>引用传递 ：方法接收的直接是实参所引用的对象在堆中的地址，不会创建副本，对形参的修改将影响到实参。</li>
</ul>
<p>如果参数是基本类型，传递的就是基本类型的<strong>字面量值的拷贝</strong>，会创建副本。<br>如果参数是引用类型，传递的就是实参所引用的对象在堆中<strong>地址值的拷贝</strong>，同样也会创建副本。</p>
<hr>
<h4 id="代理模式"><a href="#代理模式" class="headerlink" title="代理模式"></a>代理模式</h4><p><strong>使用代理对象来代替对真实对象</strong>(real object)的访问，这样就可以在不修改原目标对象的前提下，提供额外的功能操作，扩展目标对象的功能。</p>
<p>代理模式的主要作用是<strong>扩展目标对象的功能</strong>，比如说在目标对象的某个方法执行前后你可以增加一些自定义的操作。</p>
<h4 id="静态代理"><a href="#静态代理" class="headerlink" title="静态代理"></a>静态代理</h4><p>静态代理：每个方法的增强都是<strong>手动完成，非常不灵活（比如接口一旦新增加方法，目标对象和代理对象都要进行修改）且麻烦(需要对每个目标类都单独写一个代理类)。</strong><br>JVM 层面来说，静态代理在<strong>编译时</strong>就将接口、实现类、代理类这些都变成了一个个实际的 class 文件。</p>
<p>静态代理实现步骤:  </p>
<ol>
<li>定义一个接口及其实现类；</li>
<li>创建一个代理类同样实现这个接口</li>
<li>将目标对象注入进代理类，然后在代理类的对应方法调用目标类中的对应方法。这样的话，4. 我们就可以通过代理类屏蔽对目标对象的访问，并且可以在目标方法执行前后做一些自己想做的事情。</li>
</ol>
<h4 id="动态代理"><a href="#动态代理" class="headerlink" title="动态代理"></a>动态代理</h4><p>相比于静态代理来说，动态代理<strong>更加灵活</strong>。不需要针对每个目标类都单独创建一个代理类，也不必须实现接口，可以直接代理实现类( CGLIB 动态代理机制)。<br>从 JVM 角度来说，动态代理是在<strong>运行时动态生成类字节码，并加载到 JVM 中</strong>。</p>
<h5 id="JDK动态代理实现步骤："><a href="#JDK动态代理实现步骤：" class="headerlink" title="JDK动态代理实现步骤："></a>JDK动态代理实现步骤：</h5><ol>
<li>定义一个接口及其实现类；</li>
<li>自定义 InvocationHandler 并重写invoke方法，在 invoke 方法中我们会调用原生方法（被代理类的方法）并自定义一些处理逻辑；</li>
<li>通过 Proxy.newProxyInstance(ClassLoader loader,Class&lt;?&gt;[] interfaces,InvocationHandler h) 方法创建代理对象；</li>
</ol>
<h5 id="CGLIB动态代理步骤"><a href="#CGLIB动态代理步骤" class="headerlink" title="CGLIB动态代理步骤"></a>CGLIB动态代理步骤</h5><ol>
<li>定义一个类；</li>
<li>自定义 MethodInterceptor 并重写 intercept 方法，intercept 用于拦截增强被代理类的方法，和 JDK 动态代理中的 invoke 方法类似；</li>
<li>通过 Enhancer 类的 create()创建代理类；</li>
</ol>
<hr>
<h4 id="IO（Java）"><a href="#IO（Java）" class="headerlink" title="IO（Java）"></a>IO（Java）</h4><p>UNIX 系统下， IO 模型一共有 5 种： 同步阻塞 I/O、同步非阻塞 I/O、I/O 多路复用、信号驱动 I/O 和异步 I/O。</p>
<h5 id="BIO（Blocking-I-O）同步阻塞I-O模型"><a href="#BIO（Blocking-I-O）同步阻塞I-O模型" class="headerlink" title="BIO（Blocking I/O）同步阻塞I/O模型"></a>BIO（Blocking I/O）同步阻塞I/O模型</h5><p>同步阻塞 IO 模型中，应用程序发起 read 调用后，会一直阻塞，直到内核把数据拷贝到用户空间。面对十万甚至百万级连接的时候，传统的 BIO 模型是无能为力的<br><img src="/images/pasted-70.png" srcset="/img/loading.gif" lazyload alt="BIO"></p>
<h5 id="NIO（Non-Blocking-I-O）多路复用I-O模型"><a href="#NIO（Non-Blocking-I-O）多路复用I-O模型" class="headerlink" title="NIO（Non-Blocking I/O）多路复用I/O模型"></a>NIO（Non-Blocking I/O）多路复用I/O模型</h5><p>java.nio 包提供了 Channel , Selector，Buffer 等抽象。它支持<strong>面向缓冲，基于通道</strong>的 I/O 操作方法。 对于<strong>高负载、高并发的（网络）应用</strong>，应使用 NIO。<br><img src="/images/pasted-71.png" srcset="/img/loading.gif" lazyload alt="NIO"></p>
<p>线程首先发起 select 调用，询问内核数据是否准备就绪，等内核把数据准备好了，用户线程再发起 read 调用。read 调用的过程（数据从内核空间 -&gt; 用户空间）还是阻塞的。<br><strong>通过减少无效的系统调用，减少了对 CPU 资源的消耗</strong>。</p>
<p><em>同步非阻塞，应用程序不断进行IO系统调用 轮询数据是否已准备好，十分消耗 CUP 资源。</em></p>
<div class="hljs code-wrapper"><pre><code class="hljs">选择器 ( Selector ) 的概念，也可以被称为 多路复用器。通过它，只需要一个线程便可以管理多个客户端连接。当客户端数据到了之后，才会为其服务。
</code></pre></div>
<h5 id="AIO（Asynchronous-I-O）异步I-O模型"><a href="#AIO（Asynchronous-I-O）异步I-O模型" class="headerlink" title="AIO（Asynchronous I/O）异步I/O模型"></a>AIO（Asynchronous I/O）异步I/O模型</h5><p>异步 IO 是基于事件和回调机制实现的，也就是应用操作之后会直接返回，不会堵塞在那里，当后台处理完成，操作系统会通知相应的线程进行后续的操作。<br><em>Netty 使用过 AIO 但是放弃了，因为在 Linux 系统上的性能提升不大。</em></p>
<hr>
<h3 id="JDK8-新特性"><a href="#JDK8-新特性" class="headerlink" title="JDK8 新特性"></a>JDK8 新特性</h3><ul>
<li>新 interface 的方法可以用default 或 static修饰，这样就可以有方法体，实现类也不必重写此方法。解决 Interface 可以重写修改的时候，实现它的类也必须跟着改问题。</li>
<li>Lambda表达式：替代匿名内部类，集合迭代。</li>
</ul>
<hr>
<h3 id="容器"><a href="#容器" class="headerlink" title="容器"></a>容器</h3><p><img src="/images/pasted-72.png" srcset="/img/loading.gif" lazyload alt="容器框架图"></p>
<h4 id="四个接口的区别"><a href="#四个接口的区别" class="headerlink" title="四个接口的区别"></a>四个接口的区别</h4><ul>
<li>List (有序): 存储的元素是有序的、可重复的。</li>
<li>Set (不可重复): 存储的元素是无序的、不可重复的。</li>
<li>Queue (实现排队功能): 按特定的排队规则来确定先后顺序，存储的元素是有序的、可重复的。</li>
<li>Map (用 key 来搜索): 使用键值对（key-value）存储，类似于数学上的函数 y=f(x)，”x” 代表 key，”y” 代表 value，key 是无序的、不可重复的，value 是无序的、可重复的，每个键最多映射到一个值。</li>
</ul>
<h4 id="List"><a href="#List" class="headerlink" title="List"></a>List</h4><ul>
<li>Vector 是 List 的古老实现类，底层使用 <strong>Object[ ] 存储，线程安全</strong>的。</li>
<li>ArrayList 是 List 的主要实现类，底层使用 <strong>Object[ ]存储，适用于频繁的查找工作，线程不安全</strong>。</li>
<li>LinkedList 底层使用 <strong>双向链表存储，适合于频繁的删除插入操作，线程不安全</strong>。</li>
</ul>
<hr>
<h4 id="Set"><a href="#Set" class="headerlink" title="Set"></a>Set</h4><ul>
<li><p>comparable 接口实际上是出自java.lang包 它有一个 compareTo(Object obj)方法用来排序</p>
</li>
<li><p>comparator接口实际上是出自 java.util 包它有一个compare(Object obj1, Object obj2)方法用来排序</p>
</li>
<li><p>HashSet、LinkedHashSet 和 TreeSet 都是 Set 接口的实现类，都能保证元素唯一，并且都不是线程安全的。</p>
</li>
</ul>
<h5 id="HashSet、LinkedSet、TreeSet-的区别"><a href="#HashSet、LinkedSet、TreeSet-的区别" class="headerlink" title="HashSet、LinkedSet、TreeSet 的区别"></a>HashSet、LinkedSet、TreeSet 的区别</h5><ul>
<li><p>底层数据结构不同：<br>HashSet 的底层数据结构是<strong>哈希表（基于 HashMap 实现）</strong>；<br>LinkedHashSet 的底层数据结构是<strong>链表和哈希表</strong>，元素的插入和取出顺序满足 FIFO；<br>TreeSet 底层数据结构是<strong>红黑树</strong>，元素是有序的，排序的方式有自然排序和定制排序。</p>
</li>
<li><p>因此应用场景不同：<br>HashSet 用于不需要保证元素插入和取出顺序的场景；<br>LinkedHashSet 用于保证元素的插入和取出顺序满足 FIFO 的场景；<br>TreeSet 用于支持对元素自定义排序规则的场景。</p>
</li>
</ul>
<hr>
<h4 id="Queue、Deque"><a href="#Queue、Deque" class="headerlink" title="Queue、Deque"></a>Queue、Deque</h4><h5 id="Queue、Deque的区别"><a href="#Queue、Deque的区别" class="headerlink" title="Queue、Deque的区别"></a>Queue、Deque的区别</h5><ul>
<li><p>Queue 是单端队列，只能从一端插入元素，另一端删除元素，实现上一般遵循 先进先出（FIFO） 规则；</p>
</li>
<li><p>Queue 扩展了 Collection 的接口，根据 因为容量问题而导致操作失败后处理方式的不同 可以分为两类方法: add() 在操作失败后会抛出异常，offer() 则会返回特殊值。</p>
</li>
<li><p>Deque 是双端队列，在队列的两端均可以插入或删除元素。</p>
</li>
<li><p>Deque 扩展了 Queue 的接口, 增加了在队首和队尾进行插入和删除的方法，同样根据失败后处理方式的不同分为两类。</p>
</li>
</ul>
<h5 id="ArrayDeque-与-LinkedList-的区别"><a href="#ArrayDeque-与-LinkedList-的区别" class="headerlink" title="ArrayDeque 与 LinkedList 的区别"></a>ArrayDeque 与 LinkedList 的区别</h5><ul>
<li>ArrayDeque 是基于可变长的数组和双指针来实现，不支持存储 NULL 数据。  </li>
<li>ArrayDeque 插入时可能存在扩容过程, 不过均摊后的插入操作依然为 O(1)。虽然 LinkedList 不需要扩容，但是每次插入数据时均需要申请新的堆空间，均摊性能相比更慢。</li>
<li>选用 ArrayDeque 来实现队列要比 LinkedList 性能更好。</li>
</ul>
<h5 id="PriorityQueue"><a href="#PriorityQueue" class="headerlink" title="PriorityQueue"></a>PriorityQueue</h5><ul>
<li>利用了二叉堆的数据结构来实现的，底层使用可变长的数组来存储数据</li>
<li>通过堆元素的上浮和下沉，实现了在 O(logn) 的时间复杂度内插入元素和删除堆顶元素。</li>
<li>与 Queue 的区别在于元素出队顺序是与优先级相关的，即总是优先级最高的元素先出队。</li>
<li>是非线程安全的，且不支持存储 NULL 和 non-comparable 的对象。</li>
<li>默认是小顶堆，但可以接收一个 Comparator 作为构造参数，从而来自定义元素优先级的先后。</li>
</ul>
<hr>
<h4 id="Map"><a href="#Map" class="headerlink" title="Map"></a>Map</h4><h5 id="HashMap-和-HashTable-的区别"><a href="#HashMap-和-HashTable-的区别" class="headerlink" title="HashMap 和 HashTable 的区别"></a>HashMap 和 HashTable 的区别</h5><ul>
<li>HashMap 是非线程安全的，Hashtable 是线程安全的,因为 Hashtable 内部的方法基本都经过synchronized 修饰。（如果你要保证线程安全的话就使用 ConcurrentHashMap ）；</li>
<li>HashMap 要比 Hashtable 效率高一点；</li>
<li>HashMap 可以存储 null 的 key 和 value，但 null 作为键只能有一个，null 作为值可以有多个；Hashtable 不允许有 null 键和 null 值，否则会抛出 NullPointerException；</li>
<li>创建时如果不指定容量初始值，Hashtable 默认的初始大小为 11，之后每次扩充，容量变为原来的 2n+1。HashMap 默认的初始化大小为 16。之后每次扩充，容量变为原来的 2 倍。② 创建时如果给定了容量初始值，那么 Hashtable 会直接使用你给定的大小，而 HashMap 会将其扩充为 2 的幂次方大小（HashMap 中的tableSizeFor()方法保证）；</li>
<li>HashMap 在解决哈希冲突时有了较大的变化，当链表长度大于阈值（默认为 8）（将链表转换成红黑树前会判断，如果当前数组的长度小于 64，那么会选择先进行数组扩容，而不是转换为红黑树）时，将链表转化为红黑树，以减少搜索时间。Hashtable没有改变</li>
</ul>
<h5 id="HashMap-和-HashSet-区别"><a href="#HashMap-和-HashSet-区别" class="headerlink" title="HashMap 和 HashSet 区别"></a>HashMap 和 HashSet 区别</h5><p>HashSet 底层就是基于 HashMap 实现的。HashSet 除了 clone()、writeObject()、readObject()是 HashSet 自己不得不实现之外，其他方法都是直接调用 HashMap 中的方法。</p>
<h5 id="HashMap-和-TreeMap-区别"><a href="#HashMap-和-TreeMap-区别" class="headerlink" title="HashMap 和 TreeMap 区别"></a>HashMap 和 TreeMap 区别</h5><p>TreeMap 和 HashMap 都继承自 AbstractMap ，但是 TreeMap 还有对集合内元素的搜索的能力（<strong>实现了 NavigableMap 接口</strong>）和 对集合中的元素根据键排序的能力（<strong>实现了 SortedMap 接口</strong>）。</p>
<h5 id="ConcurrentHashMap-和-HashTable-的区别"><a href="#ConcurrentHashMap-和-HashTable-的区别" class="headerlink" title="ConcurrentHashMap 和 HashTable 的区别"></a>ConcurrentHashMap 和 HashTable 的区别</h5><ul>
<li><p>底层数据结构，ConcurrentHashMap 是分段数组 + 链表 —&gt; 数组 + 链表/红黑树；HashTable 就是数组 + 链表。</p>
</li>
<li><p>ConcurrentHashMap：并发控制使用 synchronized 和 CAS 来操作；<br>Hashtable (全表锁)：使用 synchronized 来保证线程安全，但是效率非常低。当一个线程访问同步方法时，其他线程也访问同步方法，可能会进入阻塞或轮询状态，如使用 put 添加元素，另一个线程不能使用 put 添加元素，也不能使用 get，竞争会越来越激烈效率越低。</p>
</li>
</ul>
<hr>
<h4 id="源码原理"><a href="#源码原理" class="headerlink" title="源码原理"></a>源码原理</h4><h5 id="ArrayList扩容机制"><a href="#ArrayList扩容机制" class="headerlink" title="ArrayList扩容机制"></a>ArrayList扩容机制</h5><ol>
<li>不指定容量，无参构造函数初始化空数组。</li>
<li>add() 前会先调用 ensureCapacityInternal()，将 minCapacity (默认为 0） = max（DEFAULT_CAPACITY（默认为10）, minCapacity（默认是1））;</li>
<li>调用ensureExplicitCapacity()，判断 minCapacity - length = （这里是10） &gt; 0 ;</li>
<li>grow()：<strong>int newCapacity = oldCapacity + (oldCapacity &gt;&gt; 1)</strong> ;</li>
</ol>
<p>ArrayList 每次扩容之后容量都会变为原来的 <strong>1.5 倍左右</strong>（oldCapacity 为偶数就是 1.5 倍，否则是 1.5 倍左右）！ 奇偶不同，比如 ：10+10/2 = 15, 33+33/2=49。如果是奇数的话会丢掉小数.</p>
<h5 id="HashMap-底层原理"><a href="#HashMap-底层原理" class="headerlink" title="HashMap 底层原理"></a>HashMap 底层原理</h5><figure class="highlight java"><table><tr><td class="gutter hljs"><div class="hljs code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><div class="hljs code-wrapper"><pre><code class="hljs java"><span class="hljs-comment">//hash方法</span><br><span class="hljs-keyword">return</span> (key == <span class="hljs-keyword">null</span>) ? <span class="hljs-number">0</span> : (h = key.hashCode()) ^ (h &gt;&gt;&gt; <span class="hljs-number">16</span>);<br></code></pre></div></td></tr></table></figure>
<p>当链表长度大于阈值（默认为 8），<strong>调用 treeifyBin()</strong> 检查当前数组的长度：如果小于 64，那么会选择先进行数组扩容 resize() 原数组 * 2，而不是转换为红黑树；大于等于 64，将链表转化为红黑树，以减少搜索时间。</p>
<p><strong>put()</strong><br>调用内部的putVal():</p>
<ol>
<li>使用hashcode 定位，如果定位到的数组位置没有元素就直接插入。</li>
<li>如果定位到的数组位置有元素就和要插入的 key 进行 equals() 比较，如果 key 相同就直接覆盖，如果 key 不相同，就判断 p 是否是一个树节点，如果是就调用 e = ((TreeNode&lt;K,V&gt;)p).putTreeVal(this, tab, hash, key, value)将元素添加进入。如果不是就遍历链表插入链表尾部)。</li>
</ol>
<h5 id="为什么是2的幂次方-HashMap"><a href="#为什么是2的幂次方-HashMap" class="headerlink" title="为什么是2的幂次方 - HashMap"></a>为什么是2的幂次方 - HashMap</h5><p>散列值使用之前要先做对数组的长度取模运算得到余数，即为存放的位置也就是对应的数组下标。<br>这个数组下标的计算方法是 <strong>(n - 1) &amp; hash</strong>（n 代表数组长度）。</p>
<div class="hljs code-wrapper"><pre><code class="hljs">取余(%)操作中如果除数是 2 的幂次则等价于与其除数减一的与(&amp;)操作（也就是说 hash%length==hash&amp;(length-1)，前提是 length 是 2 的 n 次方）。” 并且 采用二进制位操作 &amp;，相对于%能够提高运算效率。
</code></pre></div>

            </div>
            <hr>
            <div>
              <div class="post-metas mb-3">
                
                
                  <div class="post-meta">
                    <i class="iconfont icon-tags"></i>
                    
                      <a class="hover-with-bg" href="/tags/%E5%AE%9E%E4%B9%A0%E9%9D%A2%E8%AF%95/">实习面试</a>
                    
                  </div>
                
              </div>
              
                <p class="note note-warning">
                  
                    本博客所有文章未经允许，严禁转载！
                  
                </p>
              
              
                <div class="post-prevnext">
                  <article class="post-prev col-6">
                    
                    
                      <a href="/2022/04/02/JavaGuide%E6%95%B4%E7%90%86-2/">
                        <i class="iconfont icon-arrowleft"></i>
                        <span class="hidden-mobile">JavaGuide整理-2</span>
                        <span class="visible-mobile">上一篇</span>
                      </a>
                    
                  </article>
                  <article class="post-next col-6">
                    
                    
                      <a href="/2022/03/24/%E7%AE%97%E6%B3%95--%E6%8E%92%E5%BA%8F/">
                        <span class="hidden-mobile">算法---排序</span>
                        <span class="visible-mobile">下一篇</span>
                        <i class="iconfont icon-arrowright"></i>
                      </a>
                    
                  </article>
                </div>
              
            </div>

            
          </article>
        </div>
      </div>
    </div>
    
      <div class="d-none d-lg-block col-lg-2 toc-container" id="toc-ctn">
        <div id="toc">
  <p class="toc-header"><i class="iconfont icon-list"></i>&nbsp;目录</p>
  <div class="toc-body" id="toc-body"></div>
</div>

      </div>
    
  </div>
</div>

<!-- Custom -->


    

    
      <a id="scroll-top-button" aria-label="TOP" href="#" role="button">
        <i class="iconfont icon-arrowup" aria-hidden="true"></i>
      </a>
    

    
      <div class="modal fade" id="modalSearch" tabindex="-1" role="dialog" aria-labelledby="ModalLabel"
     aria-hidden="true">
  <div class="modal-dialog modal-dialog-scrollable modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-header text-center">
        <h4 class="modal-title w-100 font-weight-bold">搜索</h4>
        <button type="button" id="local-search-close" class="close" data-dismiss="modal" aria-label="Close">
          <span aria-hidden="true">&times;</span>
        </button>
      </div>
      <div class="modal-body mx-3">
        <div class="md-form mb-5">
          <input type="text" id="local-search-input" class="form-control validate">
          <label data-error="x" data-success="v"
                 for="local-search-input">关键词</label>
        </div>
        <div class="list-group" id="local-search-result"></div>
      </div>
    </div>
  </div>
</div>
    

    
  </main>

  <footer class="text-center mt-5 py-3">
  <div class="footer-content">
     CC <i class="iconfont icon-love"></i> XX
  </div>
  
  <div class="statistics">
    
    

    
      
        <!-- 不蒜子统计PV -->
        <span id="busuanzi_container_site_pv" style="display: none">
            总访问量 
            <span id="busuanzi_value_site_pv"></span>
             次
          </span>
      
      
        <!-- 不蒜子统计UV -->
        <span id="busuanzi_container_site_uv" style="display: none">
            总访客数 
            <span id="busuanzi_value_site_uv"></span>
             人
          </span>
      
    
  </div>


  

  
</footer>


  <!-- SCRIPTS -->
  
  <script  src="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.js" ></script>
  <link  rel="stylesheet" href="https://cdn.jsdelivr.net/npm/nprogress@0/nprogress.min.css" />

  <script>
    NProgress.configure({"showSpinner":false,"trickleSpeed":100})
    NProgress.start()
    window.addEventListener('load', function() {
      NProgress.done();
    })
  </script>


<script  src="https://cdn.jsdelivr.net/npm/jquery@3/dist/jquery.min.js" ></script>
<script  src="https://cdn.jsdelivr.net/npm/bootstrap@4/dist/js/bootstrap.min.js" ></script>
<script  src="/js/events.js" ></script>
<script  src="/js/plugins.js" ></script>

<!-- Plugins -->


  <script  src="/js/local-search.js" ></script>



  
    
      <script  src="/js/img-lazyload.js" ></script>
    
  



  



  
    <script  src="https://cdn.jsdelivr.net/npm/tocbot@4/dist/tocbot.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@3/dist/jquery.fancybox.min.js" ></script>
  
  
    <script  src="https://cdn.jsdelivr.net/npm/anchor-js@4/anchor.min.js" ></script>
  
  
    <script defer src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js" ></script>
  



  <script defer src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js" ></script>




  <script  src="https://cdn.jsdelivr.net/npm/typed.js@2/lib/typed.min.js" ></script>
  <script>
    (function (window, document) {
      var typing = Fluid.plugins.typing;
      var title = document.getElementById('subtitle').title;
      
        typing(title);
      
    })(window, document);
  </script>















<!-- 主题的启动项 保持在最底部 -->
<script  src="/js/boot.js" ></script>


</body>
</html>
